package com.fausto.learnimprint.utils

import com.fausto.learnimprint.common.lang.Option
import com.fausto.learnimprint.common.lang.Option.*
import org.springframework.stereotype.Component
import javax.servlet.http.HttpServletRequest

/**
 *      获取客户端的IP地址的方法是：request.getRemoteAddr（），这种方法在大部分情况下都是有效的。
 *      但是在通过了Apache，Squid，nginx等反向代理软件就不能获取到客户端的真实IP地址了。
 *      如果使用了反向代理软件，将http://192.168.1.110：2046/ 的URL反向代理为 http://www.javapeixun.com.cn / 的URL时，
 *      用request.getRemoteAddr（）方法获取的IP地址是：127.0.0.1　或　192.168.1.110，而并不是客户端的真实IP。
 *      经过代理以后，由于在客户端和服务之间增加了中间层，因此服务器无法直接拿到客户端的IP，服务器端应用也无法直接通过转发请求的地址返回给客户端。
 *      但是在转发请求的HTTP头信息中，增加了X－FORWARDED－FOR信息。用以跟踪原有的客户端IP地址和原来客户端请求的服务器地址。
 *      当我们访问http://www.javapeixun.com.cn /index.jsp/ 时，其实并不是我们浏览器真正访问到了服务器上的index.jsp文件，
 *      而是先由代理服务器去访问http://192.168.1.110：2046/index.jsp ，代理服务器再将访问到的结果返回给我们的浏览器，
 *      因为是代理服务器去访问index.jsp的，所以index.jsp中通过request.getRemoteAddr（）的方法获取的IP实际上是代理服务器的地址，
 *      并不是客户端的IP地址。
 */
@Component
class RequestUtil {

    fun getIpAddress(request: HttpServletRequest): Option<String>{
        var ip = request.getHeader("x-forwarded-for")
        when {
            ip == null || ip.isEmpty() || "unknown".equals(ip, ignoreCase = true) -> {
                ip = request.getHeader("Proxy-Client-IP")
            }

            ip == null || ip.isEmpty() || "unknown".equals(ip, ignoreCase = true) -> {
                ip = request.getHeader("WL-Proxy-Client-IP")
            }

            ip == null || ip.isEmpty() || "unknown".equals(ip, ignoreCase = true) -> {
                ip = request.getHeader("HTTP_CLIENT_IP")
            }

            ip == null || ip.isEmpty() || "unknown".equals(ip, ignoreCase = true) -> {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR")
            }

            ip == null || ip.isEmpty() || "unknown".equals(ip, ignoreCase = true) -> {
                ip = request.remoteAddr
            }

            // 如果是多级代理，那么取第一个ip为客户端ip
            ip != null && ip.indexOf(",") != -1 -> {
                ip = ip.substring(0, ip.indexOf(",")).trim { it <= ' ' }
            }
        }
        return if (null == ip){
            None()
        }else{
            Some(ip)
        }
    }
//    fun getIpAddress(request: HttpServletRequest): Option<String> {
//
//        var ip = ipHeaderList().filter {
//            !isIpNull(request.getHeader(it.content))
//        }.map {
//            request.getHeader(it.content)
//        }.last()
//
//        ip = when {
//            isIpNull(ip) -> {
//                request.remoteAddr
//            }
//            (ip != null && ip.indexOf(",") != -1) -> {
//                ip.substring(0, ip.indexOf(",")).trim{ it <= ' '}
//            }
//            else -> return None()
//        }
//
//        return Some(ip)
//    }
//
//    private fun isIpNull(ip: String?): Boolean {
//        return ip == null || ip.isEmpty() || "unknown".equals(ip, ignoreCase = true)
//    }
//
//    private fun ipHeaderList(): List<IpHeader> {
//        return listOf(
//            IpHeader.X_FORWARDED_FOR,
//            IpHeader.PROXY_CLIENT_IP,
//            IpHeader.WL_PROXY_CLIENT_IP,
//            IpHeader.HTTP_CLIENT_IP,
//            IpHeader.HTTP_X_FORWARDED_FOR
//        )
//    }
}

enum class IpHeader(val content: String) {
    X_FORWARDED_FOR("x-forwarded-for"),

    PROXY_CLIENT_IP("Proxy-Client-IP"),

    WL_PROXY_CLIENT_IP("WL-Proxy-Client-IP"),

    HTTP_CLIENT_IP("HTTP_CLIENT_IP"),

    HTTP_X_FORWARDED_FOR("HTTP_X_FORWARDED_FOR"),
}